# -*- coding:utf-8 -*- #
from engine import mysql_connction #, redis_conn
import json
from Queue import Queue
from threading import Thread
import time

#引入上层目录模块方法
import sys
sys.path.append("..")
from logger.logger import getlogger
import configure


def get_oid_by_item_id(item_id):
    sql = "select oid from ma_item where item_id='%s'" % item_id
    r = query_sql(sql)
    return [x for y in r for x in y]

def get_item_ids(oids):
    import types
    if type(oids) not in [types.TupleType, types.ListType]:
        print 'invalid parameter'
        return []
    if not oids:
        return []
    sql = ("select item_id from ma_item where oid='%s'" % oids[0])
    for o in oids[1:]:
        sql = "%s or oid='%s'" % (sql, o)

    r = query_sql(sql)
    return [x for y in r for x in y]

def execute_sql(sql):

    mysql = mysql_connction
    cursor = mysql()
    try:
        cursor.execute(sql)
    except:
        cursor = mysql(reconnect=True)
        cursor.execute(sql)

def query_sql(sql):
    """return execute result"""
    cursor = mysql_connction()
    try:
        num = cursor.execute(sql)
    except:
        cursor = mysql_connction(reconnect=True)
        num = cursor.execute(sql)
    if num:
        return cursor.fetchall()
    return []

def get_items_by_kind(kind):
    """return (oid, id) which app_id is alarm"""

    if kind == 'monitor':
        pass
    elif kind == 'alarm':
        sql = "select oid, item_id from ma_item where app_id=2"
        return query_sql(sql)
    elif kind == 'logger':
        pass
    else:
        return []

def get_contents(table, ids, interval=None, num=None):
    """
    if you just want to get contents from ma_item, set interval and num default
    if you want to get data from other tables, you must specify interval zone and
    data number.

    get_contents('ma_item', [1, 2, 3]) => return data from ma_item which
    item_id is 1 or 2 or 3
    get_contents('ma_monitor_data_YYMMDD', [1, 2, 3], [0, time.time()], 100)
    => return 100 data from ma_monitor_data_YYMMDD which id is 1 or 2 or 3 and
    time zone x must be 0 < x < time.time()

    table dict return:
        ma_item =>
        {'item_id': item_id, 'app_id': app_id, 'tname': tname,
        'last_time': last_time, 'last_data': last_data}

        ma_monitor_data_YYMMDD, ma_logger, ma_alarm =>
        {'item_id': item_id, 'content': content, 'datetime': datetime}
    """
    #print table, ids, time, num
    if table == 'ma_item':
        return _get_ma_item_contents(ids)
    elif table in ['ma_monitor_data_YYMMDD', 'ma_alarm_data', 'ma_log_data']:
        return _get_others(table, ids, interval, num)
    else:
        return [{'msg': 1}]


def _get_ma_item_contents(ids):
    """app_id: 1 => monitor, 2 => alarm, 3 => logger"""
    cursor = mysql_connction()
    sql = 'select oid, app_id, t_name, item_id from ma_item where item_id=%s' % ids[0]
    sql = reduce(lambda x, y: x + ' or item_id=' + str(y), ids[1:], sql)
    cursor.execute(sql)

    # get data and compose data
    conn = redis_conn()
    contents = []

    for item in cursor.fetchall():
        c = {'oid': item[0], 'app_id': item[1],
                'tname': item[2], 'item_id': item[3]
               }
        if int(item[1]) == 1:
            c['last_time'] = conn.get('%s.m_last_time' % item[3])
            c['content'] = conn.get('%s.m_last_data' % item[3])
            c['is_attention'] = conn.get('%s.m_is_attention' % item[3])
        elif int(item[1]) == 2:
            c['last_time'] = conn.get('%s.a_last_time' % item[3])
            c['count'] = conn.get('%s.a_count' % item[3])
        elif int(item[1]) == 3:
            c['last_time'] = conn.get('%s.l_last_time' % item[3])
            c['count'] = conn.get('%s.l_count' % item[3])
        contents.append(c)

    return contents

def _pick_data(values, num):
    """
    pick up num items from values
    """

    #print values[0]
    if len(values) < num:
        return values
    else:
        step = len(values) / num
        vs = []
        vs.extend(
                [v for k, v in enumerate(values) if k % step == 0]
                )
        return vs


def _get_others(table, ids, interval, num):
    """get contents from ma_monitor_data_YYMMDD, ma_alarm_data, ma_log_data"""
    contents = []
    conn = redis_conn()

    try:
        begin = interval[0]
        end = interval[1]
    except  TypeError as e:
        getlogger(configure.logger_path).error('time:%s should be list' % e.message)
    except IndexError as e:
        getlogger(configure.logger_path).error('time:%s length is not correct' % e.message)
        return


    contents = []
    queue = Queue()
    gens = []
    #ps = []

    size = 0
    for i in ids:
        #print begin, conn.hkeys('m.%s' % i), end
        if table == 'ma_monitor_data_YYMMDD':
            fields = filter(lambda x: begin <= int(float(x)) <= end,
                    conn.lrange(i, 0, -1))
            size += 1

            r = reduce_data(i, fields, num, table, queue)
            gens.append(r)
        elif table == 'ma_alarm_data':
            #fields = filter(lambda x: begin <= int(float(x)) <= end,
                #conn.lrange(i, 0, -1))
            fields = conn.lrange(i, 0, -1)
            #fields = _pick_data(fields, num)
            for f in fields:
                c = {'item_id': i,}
                c['begin_time'] = f
                solved_level = current_level = content = end_time = None
                if conn.exists('%s.%s.solved'):
                    try:
                        end_time, content  = conn.hgetall('%s.%s.solved' % (i, f))
                        current_level = 0
                        solved_level = conn.hkeys('%s.%s' % (i, f))[-1]
                    except IndexError:
                        pass
                else:
                    r = conn.hgetall('%s.%s' % (i, f))
                    try:
                        k = sorted(r.keys())[-1]
                    except IndexError:
                        pass
                    else:
                        current_level, content = k, r[k]
                c['end_time'] = end_time
                c['current_level'] = current_level
                c['content'] = content
                c['solved_level'] = solved_level
                contents.append(c)

        #elif table == 'ma_alarm_data':
            #fields = filter(lambda x: begin <= int(float(x)) <= end,
                #conn.lrange(i, 0, -1))
            #fields = _pick_data(fields, num)
            #for f in fields:
                #c = {'item_id': i,}
                #c['begin_time'] = f
                #c['solved'] = conn.exists('%s.%s.solved')
                #contents.append(c)

        elif table == 'ma_log_data':
            fields = filter(lambda x: begin <= int(float(x)) <= end,
                conn.lrange(i, 0, -1))
            #fields = _pick_data(fields, num)
            for f in fields:
                c = {'item_id': i,}
                c['datetime'] = f
                c['content'] = conn.hget('%s.%s' % (i, f), 0)
                contents.append(c)

    if table == 'ma_monitor_data_YYMMDD':
        scheme(gens)
        for i in range(size):
            item = queue.get()
            contents.extend(item)

    return contents

def scheme(gens):
    for g in gens:
        g.next()

    print 'finish scheme'

def reduce_data(item_id, fields, num, table, queue):
    while True:
        yield _reduce_data(item_id, fields, num, table, queue)


def _reduce_data(item_id, fields, num, table, queue):
    i = item_id
    conn = redis_conn()
    if table == 'ma_monitor_data_YYMMDD':
        p = conn.pipeline()
        contents = []
        for f in fields:
            p.hgetall('%s.%s' % (i, f))
        pi = iter(p.execute())

        for f in fields:
            c = {'item_id': i,}
            c['datetime'] = f
            its = pi.next().items()
            if not its:
                continue
            c['is_attention'], c['content'] = its[0]
            contents.append(c)
        queue.put(_reduce_pick_data(contents, num))

def _reduce_pick_data(values, num):
    """
    pick up num items from values
    return the weighted average of intervals
    """

    if len(values) < num:
        return values
    else:
        step = len(values) / num
        vs = []
        data = values[0]
        acc = eval(data['content'])
        datetime = float(data['datetime'])
        total = 0
        for n, v in enumerate(values[1:]):
            total = total + 1
            if n % step == 0 and n != 0:
                def cal_average(data, total):
                    for k, v in data.iteritems():
                        data[k] = [float(v[0]) / total, data[k][1]]
                    return data

                acc = cal_average(acc, total)
                data.update({'datetime': datetime / total, 'content': '%s' % json.dumps(acc)})
                vs.append(data)
                if len(vs) >= num:
                    break
                data = v
                acc = eval(v['content'])
                datetime = float(v['datetime'])
                total = 0
            else:
                content = eval(v['content'])
                datetime += float(v['datetime'])
                for k in content.iterkeys():
                    if k not in acc:
                        acc[k] = content[k]
                    acc[k] = [float(acc[k][0]) + float(content[k][0]), acc[k][1]]
        return vs


